library("tidyr")
library('ggplot2')
library('dplyr')
library("glue")
library('ggVennDiagram')
wkdir = "~/Desktop/GitHub/Obesity/NewExtractions/H9N2/timo_0.01"
setwd(wkdir)
savedir = "~/Desktop/GitHub/Obesity/NewExtractions/H9N2/timo_0.01/Output_Figures"
source("~/Desktop/GitHub/Obesity/NewExtractions/H9N2/FD_functions.R")
diet = c("Obese","Lean","Control")
dietColors = c("#FF9933","#66CCFF","#606060")
names(dietColors) = diet
DietcolScale_fill <- scale_fill_manual(name = "grp",values = dietColors)
DietcolScale <- scale_colour_manual(name = "grp",values = dietColors)
Specifying thresholds and plotting variables
cov_cut = 200
freq_cut = 0.01
pvalcut = 0.05
ntlist = c("A","C","G","T")
SEGMENTS = c('H9N2_PB2','H9N2_PB1','H9N2_PA','H9N2_HA','H9N2_NP','H9N2_NA','H9N2_MP','H9N2_NS')
#Loading metadata This includes titer and Ct values when applicable.
ND indicates qPCR was run with a negative result; 0 indicates plaque
assay or HAI was run with a negative result. NA for any values indicate
that data was missing. Sacrificed indicates there was no data at that
time point because the ferret had already been sacrficied for
pathology.
metafile = metafile = "~/Desktop/GitHub/Obesity/NewExtractions/H9N2/H9_Metadata.csv"
meta = read.csv(file=metafile,header=T,sep=",",na.strings = c(''))
meta = filter(meta, resequenced == "yes")
meta$Ct_Mgene = as.numeric(meta$Ct_Mgene)
Warning: NAs introduced by coercion
meta$titer = as.numeric(meta$titer)
Warning: NAs introduced by coercion
meta$log10_titer = as.numeric(meta$log10_titer)
Warning: NAs introduced by coercion
meta$inf_route = factor(meta$inf_route, levels = c("Index","Contact","Aerosol","Control"))
Loading in coverage file & segment size information
cov = read.csv("./avg_coverage/H9N2.coverage.csv", header = TRUE, sep = ",")
seg_sizes = "../SegmentSize.csv"
sizes = read.csv(file=seg_sizes,header=T,sep=",",na.strings = c(''))
GenomeSize = (sizes %>% filter(segment == 'H9N2_GENOME'))$SegmentSize
cov$segment = factor(cov$segment, levels = SEGMENTS)
Checking if data passes thresholds
cov_check = CoverageAcross(cov,cov_cut,40,sizes, wkdir)
Coverage cutoff is: 200x
Percentage covered cutoff is: 40%
Merging coverage check info with the rest of the metadata
meta = merge(meta, cov_check, by.x = c("sample"), by.y = c("name"), all.y = TRUE)
nrow(meta)
[1] 1536
count(meta,quality)
Loading in variant files
varfile = "./varfiles/H9N2.VariantsOnly.0.01.200.csv"
# read and rearrange the data
vars = read.csv(file=varfile,header=T,sep=",",na.strings = c(''))
vars$name = vars$sample
Rearranging variant dataframe
vdf = ArrangeVarWRep(vars)
# already have replicate data in the varfiles from running CompareReps.v2.py script
vdf = vdf[!duplicated(vdf), ] %>% droplevels()
nrow(vdf)
[1] 1781
Filtering variant df by timo binocheck
vdf$binocheck = factor(vdf$binocheck, levels = c("False","R1","R2","True"))
vdf_bino = filter(vdf, binocheck != "False")
vdf_bino = vdf_bino[!duplicated(vdf_bino), ] %>% droplevels()
nrow(vdf_bino)
[1] 1166
# this really gets rid of a lot of variants (~1000)
Filtering variant df with frequency cutoffs
vdf = filter(vdf, minorfreq1 >= freq_cut &
minorfreq2 >= freq_cut &
minor %in% ntlist &
major %in% ntlist) %>%
droplevels()
# based on MAF study, reps and 0.01% cutoff was best combo
#filter each replicate separately rather than using the average
vdf = vdf[!duplicated(vdf), ] %>% droplevels()
nrow(vdf)
[1] 1702
# does not eliminate any variants here
Adding metadata
vdf = merge(vdf,meta, by = c("sample","segment"))
vdf = vdf[!duplicated(vdf), ] %>% droplevels()
vdf$segment = factor(vdf$segment, levels = SEGMENTS)
vdf = filter(vdf, inf_route == "Index" | inf_route == "Contact" | inf_route == "Control")
# ignoring aerosol for now
vdf = filter(vdf, quality == "good")
vdf = vdf[!duplicated(vdf), ] %>% droplevels()
good_names = c(levels(factor(vdf$sample)))
transmission_info = "/Users/marissaknoll/Desktop/GitHub/Obesity/NewExtractions/H9N2/TransmissionPairs.csv"
pairs = read.csv(transmission_info, header = T)
con_change = filter(vdf, stocknt != major) %>%
filter(major %in% ntlist)
con_change = con_change[!duplicated(con_change), ]
con_change$ntvar = paste0(con_change$ferretID,"_",con_change$segment,"_",
con_change$major,"_",con_change$ntpos,"_",con_change$minor)
consensus = unique(con_change$ntvar)
length(consensus)
[1] 13
vdf$ntvar = paste0(vdf$ferretID,"_",vdf$segment,"_",vdf$major,"_",vdf$ntpos,"_",vdf$minor)
minorvdf = filter(vdf, !(ntvar %in% consensus)) %>% unique()
nrow(vdf) - nrow(minorvdf)
[1] 15
SNV location plots
SNVLocation = ggplot(minorvdf, aes(x = ntpos, y = ferretID)) +
geom_point(aes(color = diet, shape = cohort)) +
facet_grid(inf_route~segment) +
PlotTheme1 +
DietcolScale
print(SNVLocation)
ggsave(SNVLocation, file = "SNVLocation.pdf", path = savedir)
Saving 7.29 x 4.51 in image

# ferret 1787 doesn't have any variants??
minorvdf$ntvar = paste0(minorvdf$segment,"_",minorvdf$major,minorvdf$ntpos,minorvdf$minor)
# Comparing to SNVs found in the stock
F17_stock = filter(minorvdf, DPI == "Stock", cohort == "F17")
F17_stock_ntvar = unique(F17_stock$ntvar)
W17_stock = filter(minorvdf, DPI == "Stock", cohort == "W17")
W17_stock_ntvar = unique(W17_stock$ntvar)
Sm18_stock = filter(minorvdf, DPI == "Stock", cohort == "Sm18")
Sm18_stock_ntvar = unique(Sm18_stock$ntvar)
Sp19_stock = filter(minorvdf, DPI == "Stock", cohort == "Sp19")
Sp19_stock_ntvar = unique(Sp19_stock$ntvar)
Sp20_stock = filter(minorvdf, DPI == "Stock", cohort == "Sp20")
Sp20_stock_ntvar = unique(Sp20_stock$ntvar)
F17_ferret = filter(minorvdf , cohort == "F17", inf_route != "Control")
F17_ferret_ntvar = unique(F17_ferret$ntvar)
W17_ferret = filter(minorvdf ,cohort == "W17", inf_route != "Control")
W17_ferret_ntvar = unique(W17_ferret$ntvar)
Sm18_ferret = filter(minorvdf ,cohort == "Sm18", inf_route != "Control")
Sm18_ferret_ntvar = unique(Sm18_ferret$ntvar)
Sp19_ferret = filter(minorvdf ,cohort == "Sp19", inf_route != "Control")
Sp19_ferret_ntvar = unique(Sp19_ferret$ntvar)
Sp20_ferret = filter(minorvdf ,cohort == "Sp20", inf_route != "Control")
Sp20_ferret_ntvar = unique(Sp20_ferret$ntvar)
F17_shared = F17_ferret %>% filter(ntvar %in% F17_stock_ntvar) %>% filter((ntvar %in% F17_ferret_ntvar)) %>% unique()
F17_denovo = F17_ferret %>% filter((ntvar %in% F17_ferret_ntvar)) %>% filter(!(ntvar %in% F17_stock_ntvar)) %>% unique()
W17_shared = W17_ferret %>% filter(ntvar %in% W17_stock_ntvar) %>% filter((ntvar %in% W17_ferret_ntvar)) %>% unique()
W17_denovo = W17_ferret %>% filter((ntvar %in% W17_ferret_ntvar)) %>% filter(!(ntvar %in% W17_stock_ntvar)) %>% unique()
Sm18_shared = Sm18_ferret %>% filter(ntvar %in% Sm18_stock_ntvar) %>% filter((ntvar %in% Sm18_ferret_ntvar)) %>% unique()
Sm18_denovo = Sm18_ferret %>% filter((ntvar %in% Sm18_ferret_ntvar)) %>% filter(!(ntvar %in% Sm18_stock_ntvar)) %>% unique()
Sp19_shared = Sp19_ferret %>% filter(ntvar %in% Sp19_stock_ntvar) %>% filter((ntvar %in% Sp19_ferret_ntvar)) %>% unique()
Sp19_denovo = Sp19_ferret %>% filter((ntvar %in% Sp19_ferret_ntvar)) %>% filter(!(ntvar %in% Sp19_stock_ntvar)) %>% unique()
Sp20_shared = Sp20_ferret %>% filter(ntvar %in% Sp20_stock_ntvar) %>% filter((ntvar %in% Sp20_ferret_ntvar)) %>% unique()
Sp20_denovo = Sp20_ferret %>% filter((ntvar %in% Sp20_ferret_ntvar)) %>% filter(!(ntvar %in% Sp20_stock_ntvar)) %>% unique()
stock_shared = rbind(F17_shared, W17_shared, Sm18_shared, Sp19_shared, Sp20_shared)
stock_shared$aavar = paste0(stock_shared$majoraa,stock_shared$aapos,stock_shared$minoraa)
ferunique = rbind(F17_denovo, W17_denovo, Sm18_denovo, Sp19_denovo, Sp20_denovo)
ferunique$aavar = paste0(ferunique$majoraa,ferunique$aapos,ferunique$minoraa)
SNV Location compared to stock
StockSharedPlot = ggplot(stock_shared, aes(x = ntpos, y = ferretID)) +
geom_point(aes(color = diet, shape = cohort), size = 2) +
facet_grid(inf_route~segment, drop = FALSE) +
PlotTheme1 +
DietcolScale +
ggtitle("SNVs found in stock")
print(StockSharedPlot)
ggsave(StockSharedPlot, file = "StockSharedPlot.pdf", height = 30, width = 15, path = savedir)

FerUniquePlot = ggplot(ferunique, aes(x = ntpos, y = ferretID)) +
geom_point(aes(color = diet)) +
facet_grid(inf_route~segment) +
PlotTheme1 +
DietcolScale +
ggtitle("SNVs not found in stock")
print(FerUniquePlot)
ggsave(FerUniquePlot, file = "FerUniquePlot.pdf", path = savedir)
Saving 7.29 x 4.51 in image

Venn diagram of obese and lean de novo SNVs
o_var = filter(ferunique, diet == "Obese")
o_var = unique(o_var$ntvar)
l_var = filter(ferunique, diet == "Lean")
l_var = unique(l_var$ntvar)
diet_var <- list(Obese = o_var, Lean = l_var)
DietUniqueSNVS = ggVennDiagram(diet_var)
print(DietUniqueSNVS)
ggsave(DietUniqueSNVS, file = "DietUniqueSNVS.pdf", path = savedir)
Saving 7.29 x 4.51 in image

Obese- and lean-specific SNVs
lean = ferunique %>%
filter(ntvar %in% l_var) %>%
filter(!(ntvar %in% o_var)) %>%
unique()
lean$ferretID_var = paste0(lean$ferretID,"_",lean$ntvar)
repeats_lean = lean %>%
group_by(ntvar,ferretID) %>%
tally() %>%
group_by(ntvar) %>%
tally() %>% unique()
lean = merge(lean, repeats_lean, by = c("ntvar")) %>% unique()
obese = ferunique %>%
filter(ntvar %in% o_var) %>%
filter(!(ntvar %in% l_var)) %>%
unique()
obese$ferretID_var = paste0(obese$ferretID,"_",obese$ntvar)
repeats_obese = obese %>%
group_by(ntvar,ferretID) %>%
tally() %>%
group_by(ntvar) %>%
tally() %>%
unique()
obese = merge(obese, repeats_obese, by = c("ntvar")) %>% unique()
Determining if diet-unique shared variants are transmitted
dietunique = rbind(lean,obese) %>% unique()
dietunique = merge(dietunique, pairs, by = c("ferretID"))
shared = filter(dietunique, n == 2)
t = unique(shared$ntvar)
transmitted = data.frame()
for(i in t){
print(i)
df = filter(shared, ntvar == i)
df1 = group_by(df,pair_numbers) %>% tally()
# here a 2 means that the two ferrets are in the same transmission pair and a 1 indicates different transmission pairs
df2 = merge(df, df1, by = c("pair_numbers"))
# add this information back into the dataframe
df2$transmission = df2$n.y
transmitted = rbind(transmitted, df2)
}
[1] "H9N2_MP_G459A"
[1] "H9N2_NA_G72A"
[1] "H9N2_PB2_A480G"
[1] "H9N2_NS_A719G"
[1] "H9N2_NA_G452A"
[1] "H9N2_HA_A658G"
[1] "H9N2_HA_C383A"
[1] "H9N2_PB2_A1351T"
[1] "H9N2_PB2_A482G"
[1] "H9N2_PB1_T906C"
[1] "H9N2_PB1_T905C"
[1] "H9N2_NP_T911C"
[1] "H9N2_MP_T444C"
[1] "H9N2_HA_G808A"
[1] "H9N2_HA_C802T"
[1] "H9N2_PB2_C1928G"
[1] "H9N2_NS_G294A"
[1] "H9N2_PA_G1986A"
[1] "H9N2_MP_G258A"
[1] "H9N2_MP_G339A"
[1] "H9N2_PB1_G738A"
[1] "H9N2_PB1_T1604C"
[1] "H9N2_PB1_G591A"
[1] "H9N2_HA_C375T"
[1] "H9N2_NS_G660A"
[1] "H9N2_PB2_G1320A"
[1] "H9N2_PA_C1873T"
[1] "H9N2_NA_C92T"
[1] "H9N2_NP_C249T"
[1] "H9N2_HA_A747G"
[1] "H9N2_PA_C1782A"
[1] "H9N2_HA_A1531T"
#formatting stuff
notshared = filter(dietunique, n == 1)
notshared$transmission = 0
transmitted$n = transmitted$n.x
transmitted = transmitted %>% select(!(n.x)) %>% select(!(n.y))
dietunique = rbind(notshared, transmitted)
dietunique$transmission = as.character(dietunique$transmission)
DietUnique = ggplot(dietunique, aes(x = ntpos, y = segment)) +
geom_point(aes(color = nonsyn, size = n, shape = transmission)) +
ggtitle("Number of samples containing each variant - diet specific") +
theme(legend.key = element_blank(),
strip.background = element_rect(colour="black", fill="white"),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
facet_grid(diet~STRAIN) +
PlotTheme1
print(DietUnique)

#ggsave(DietUnique, filename = "SegmentSNVPlot_DietUnqique.pdf", path = savedir, width = 10, height = 5)

Pulling out repeated nonsynonymous mutations
nonsyns = filter(dietunique, nonsyn == "nonsyn" & n > 1) %>% ungroup() %>% unique() %>% droplevels()
nonsyns_smol = select(nonsyns,ntvar,aavar,diet,inf_route,n) %>% droplevels()
write.csv(nonsyns_smol, "nonsyns.csv")
nonsyns_dietunique = filter(dietunique, nonsyn == "nonsyn" & n > 1) %>%
ungroup() %>%
select(diet,ntvar,aavar,n) %>%
unique() %>%
arrange(desc(n))
write.table(nonsyns_dietunique, "nonsyns_dietunique.csv", sep = ",", row.names = FALSE)
dNdS analysis of de novo, diet unique genes
# by ferret
dNdS_denovo_ferret = dietunique %>%
ungroup() %>%
group_by(ferretID,DPI,diet,inf_route) %>%
count(nonsyn)
dNdS_denovo_ferret = pivot_wider(dNdS_denovo_ferret,names_from = nonsyn, values_from = n)
dNdS_denovo_ferret = select(dNdS_denovo_ferret, ferretID,DPI,nonsyn,syn)
Adding missing grouping variables: `diet`, `inf_route`
dNdS_denovo_ferret$dNdS = paste0(dNdS_denovo_ferret$nonsyn / dNdS_denovo_ferret$syn)
dNdS_denovo_ferret$dNdS = as.numeric(dNdS_denovo_ferret$dNdS)
Warning: NAs introduced by coercion
dNdS_denovo_ferret_plot = ggplot(dNdS_denovo_ferret, aes(x = DPI, y = dNdS, color = ferretID)) +
geom_point() +
geom_line(aes(group = ferretID)) +
facet_grid(~diet+inf_route) +
PlotTheme1
print(dNdS_denovo_ferret_plot)
ggsave("dNdS_denovo_ferret.pdf", dNdS_denovo_ferret_plot, path = savedir)
Saving 7.29 x 4.51 in image

Which ferrets have more than one de novo?
ggplot(dietunique, aes(x = ntpos, y = ferretID)) +
geom_point(aes(color = diet)) +
facet_grid(~segment) +
PlotTheme1 +
DietcolScale

ggplot(filter(dietunique, n >1), aes(x = ntpos, y = ferretID)) +
geom_point(aes(color = diet)) +
facet_grid(~segment) +
PlotTheme1 +
DietcolScale

SNVs shared between diet groups
shared = ferunique %>%
filter(ntvar %in% o_var) %>%
filter(ntvar %in% l_var) %>%
unique()
shared$ferretID_var = paste0(shared$ferretID,"_",shared$ntvar)
repeats_shared = shared %>%
group_by(ntvar,ferretID) %>%
tally() %>%
group_by(ntvar) %>%
tally()
# this is to make sure I'm not repeatedly counting a variant found in one ferret but multiple days
shared = merge(shared, repeats_shared, by = c("ntvar"))
SharedPlot = ggplot(shared,
aes(x = ntpos,
y = factor(segment, levels = c('H9N2_NS','H9N2_MP','H9N2_NA','H9N2_NP','H9N2_HA','H9N2_PA','H9N2_PB1','H9N2_PB2')))) +
geom_point(aes(size = n, color = nonsyn)) +
ggtitle("Number of samples containing each variant - Shared between diet groups") +
theme(legend.key = element_blank(),
strip.background = element_rect(colour="black", fill="white"),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
xlab("Nucleotide position") +
ylab("Segment") +
PlotTheme1
print(SharedPlot)
ggsave(SharedPlot, filename = "SegmentSNVPlot_DietShared.pdf", path = savedir)
Saving 7.29 x 4.51 in image

Extracting common nonsynonymous variants shared between diet
groups
nonsyns_shared = filter(shared, nonsyn == "nonsyn" & n > 1) %>%
ungroup() %>%
select(ntvar,aavar,n) %>%
unique() %>%
arrange(desc(n))
write.table(nonsyns_shared, "nonsyns_shared.csv", sep = ",", row.names = FALSE)
Is there a difference in how often these variants are found in obese
v lean ferrets?
shared_vars = group_by(shared, ntvar, diet) %>% tally()
ggplot(shared_vars, aes(x = ntvar, y = n, fill = diet)) +
geom_col(position = "dodge") +
#facet_grid(~inf_route) +
PlotTheme1 +
DietcolScale_fill

diff_shared_vars = group_by(shared, ntvar, diet) %>%
tally() %>%
pivot_wider(names_from = diet, values_from = n) %>%
mutate(diff = abs(Obese - Lean)) %>%
filter(diff > 2) %>%
pivot_longer(cols = c("Lean", "Obese"), names_to = c("diet"))
ggplot(diff_shared_vars, aes(x = ntvar, y = value, fill = diet)) +
geom_col(position = "dodge") +
#facet_grid(~inf_route) +
PlotTheme1 +
DietcolScale_fill

Is there a difference in AF of the variants found in obese and lean
ferrets?
ggplot(shared, aes(x = minorfreq, fill = diet)) +
geom_histogram(binwidth = 0.01) +
PlotTheme1 +
facet_grid(inf_route~diet) +
DietcolScale_fill

o = filter(ferunique, inf_route == "Index" & diet == "Obese")
l = filter(ferunique, inf_route == "Index" & diet == "Lean")
t.test(o$minorfreq, l$minorfreq)
Welch Two Sample t-test
data: o$minorfreq and l$minorfreq
t = 0.94849, df = 455.9, p-value = 0.3434
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-0.002375118 0.006806719
sample estimates:
mean of x mean of y
0.02975715 0.02754135
#not significantly different
obese_index = filter(ferunique, diet == "Obese" & inf_route == "Index") %>% ungroup()
lean_index = filter(ferunique, diet == "Lean" & inf_route == "Index") %>% ungroup()
t.test(obese_index$minorfreq, lean_index$minorfreq)
Welch Two Sample t-test
data: obese_index$minorfreq and lean_index$minorfreq
t = 0.94849, df = 455.9, p-value = 0.3434
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-0.002375118 0.006806719
sample estimates:
mean of x mean of y
0.02975715 0.02754135
# means are not different
obese_contact = filter(ferunique, diet == "Obese" & inf_route == "Contact") %>% ungroup()
lean_contact = filter(ferunique, diet == "Lean" & inf_route == "Contact") %>% ungroup()
t.test(obese_contact$minorfreq, lean_contact$minorfreq)
Welch Two Sample t-test
data: obese_contact$minorfreq and lean_contact$minorfreq
t = 0.82593, df = 275.13, p-value = 0.4096
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-0.008413585 0.020576169
sample estimates:
mean of x mean of y
0.06003106 0.05394977
# means are not different
# QQ_Plot: compares the quantiles of two distributions, x =y suggests they are drawn from the same distribution
qqnorm(obese_index$minorfreq, main = "Obese Index - Test of Normal Distribution")

qqnorm(lean_index$minorfreq, main = "Lean Index - Test of Normal Distribution")

# neither distribution is normal
qqplot(obese_index$minorfreq,lean_index$minorfreq, xlab = "Obese Index", ylab = "Lean Index")

qqnorm(obese_contact$minorfreq, main = "Obese Contact - Test of Normal Distribution")

qqnorm(lean_contact$minorfreq, main = "Lean Contact - Test of Normal Distribution")

# neither distribution is normal
qqplot(obese_contact$minorfreq,lean_contact$minorfreq, xlab = "Obese Contact", ylab = "Lean Contact")

# Mann-Whitney-Wilcox test (Mann-Whitney U test): samples are not normally distributed and independent of each other
wilcox.test(obese_index$minorfreq,lean_index$minorfreq)
Wilcoxon rank sum test with continuity correction
data: obese_index$minorfreq and lean_index$minorfreq
W = 43671, p-value = 0.2553
alternative hypothesis: true location shift is not equal to 0
wilcox.test(obese_contact$minorfreq,lean_contact$minorfreq)
Wilcoxon rank sum test with continuity correction
data: obese_contact$minorfreq and lean_contact$minorfreq
W = 16479, p-value = 0.03287
alternative hypothesis: true location shift is not equal to 0
# distributions are not different
# Kolmogorov-Smirnov test: samples are not normally distributed and independent of each other
# "sensitive to differences in location and shape of the empirical CDFs of the two samples"
ks.test(obese_index$minorfreq,lean_index$minorfreq)
Asymptotic two-sample Kolmogorov-Smirnov test
data: obese_index$minorfreq and lean_index$minorfreq
D = 0.074336, p-value = 0.4248
alternative hypothesis: two-sided
ks.test(obese_contact$minorfreq,lean_contact$minorfreq)
Asymptotic two-sample Kolmogorov-Smirnov test
data: obese_contact$minorfreq and lean_contact$minorfreq
D = 0.1714, p-value = 0.0153
alternative hypothesis: two-sided
# distributions are not different
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoInRpZHlyIikKbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ2RwbHlyJykKbGlicmFyeSgiZ2x1ZSIpCmxpYnJhcnkoJ2dnVmVubkRpYWdyYW0nKQoKd2tkaXIgPSAifi9EZXNrdG9wL0dpdEh1Yi9PYmVzaXR5L05ld0V4dHJhY3Rpb25zL0g5TjIvdGltb18wLjAxIgpzZXR3ZCh3a2RpcikKc2F2ZWRpciA9ICJ+L0Rlc2t0b3AvR2l0SHViL09iZXNpdHkvTmV3RXh0cmFjdGlvbnMvSDlOMi90aW1vXzAuMDEvT3V0cHV0X0ZpZ3VyZXMiCgpzb3VyY2UoIn4vRGVza3RvcC9HaXRIdWIvT2Jlc2l0eS9OZXdFeHRyYWN0aW9ucy9IOU4yL0ZEX2Z1bmN0aW9ucy5SIikKYGBgCgpgYGB7cn0KZGlldCA9IGMoIk9iZXNlIiwiTGVhbiIsIkNvbnRyb2wiKQpkaWV0Q29sb3JzID0gYygiI0ZGOTkzMyIsIiM2NkNDRkYiLCIjNjA2MDYwIikKbmFtZXMoZGlldENvbG9ycykgPSBkaWV0CkRpZXRjb2xTY2FsZV9maWxsIDwtIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiZ3JwIix2YWx1ZXMgPSBkaWV0Q29sb3JzKQpEaWV0Y29sU2NhbGUgPC0gc2NhbGVfY29sb3VyX21hbnVhbChuYW1lID0gImdycCIsdmFsdWVzID0gZGlldENvbG9ycykKYGBgCgpTcGVjaWZ5aW5nIHRocmVzaG9sZHMgYW5kIHBsb3R0aW5nIHZhcmlhYmxlcwpgYGB7cn0KY292X2N1dCA9IDIwMApmcmVxX2N1dCA9IDAuMDEKcHZhbGN1dCAgPSAwLjA1CgpudGxpc3QgPSBjKCJBIiwiQyIsIkciLCJUIikKU0VHTUVOVFMgPSBjKCdIOU4yX1BCMicsJ0g5TjJfUEIxJywnSDlOMl9QQScsJ0g5TjJfSEEnLCdIOU4yX05QJywnSDlOMl9OQScsJ0g5TjJfTVAnLCdIOU4yX05TJykKYGBgCgojTG9hZGluZyBtZXRhZGF0YQpUaGlzIGluY2x1ZGVzIHRpdGVyIGFuZCBDdCB2YWx1ZXMgd2hlbiBhcHBsaWNhYmxlLiBORCBpbmRpY2F0ZXMgcVBDUiB3YXMgcnVuIHdpdGggYSBuZWdhdGl2ZSByZXN1bHQ7IDAgaW5kaWNhdGVzIHBsYXF1ZSBhc3NheSBvciBIQUkgd2FzIHJ1biB3aXRoIGEgbmVnYXRpdmUgcmVzdWx0LiBOQSBmb3IgYW55IHZhbHVlcyBpbmRpY2F0ZSB0aGF0IGRhdGEgd2FzIG1pc3NpbmcuIFNhY3JpZmljZWQgaW5kaWNhdGVzIHRoZXJlIHdhcyBubyBkYXRhIGF0IHRoYXQgdGltZSBwb2ludCBiZWNhdXNlIHRoZSBmZXJyZXQgaGFkIGFscmVhZHkgYmVlbiBzYWNyZmljaWVkIGZvciBwYXRob2xvZ3kuIApgYGB7cn0KbWV0YWZpbGUgPSBtZXRhZmlsZSA9ICJ+L0Rlc2t0b3AvR2l0SHViL09iZXNpdHkvTmV3RXh0cmFjdGlvbnMvSDlOMi9IOV9NZXRhZGF0YS5jc3YiCgptZXRhID0gcmVhZC5jc3YoZmlsZT1tZXRhZmlsZSxoZWFkZXI9VCxzZXA9IiwiLG5hLnN0cmluZ3MgPSBjKCcnKSkKbWV0YSA9IGZpbHRlcihtZXRhLCByZXNlcXVlbmNlZCA9PSAieWVzIikKCm1ldGEkQ3RfTWdlbmUgPSBhcy5udW1lcmljKG1ldGEkQ3RfTWdlbmUpCm1ldGEkdGl0ZXIgPSBhcy5udW1lcmljKG1ldGEkdGl0ZXIpCm1ldGEkbG9nMTBfdGl0ZXIgPSBhcy5udW1lcmljKG1ldGEkbG9nMTBfdGl0ZXIpCgptZXRhJGluZl9yb3V0ZSA9IGZhY3RvcihtZXRhJGluZl9yb3V0ZSwgbGV2ZWxzID0gYygiSW5kZXgiLCJDb250YWN0IiwiQWVyb3NvbCIsIkNvbnRyb2wiKSkKYGBgCgpMb2FkaW5nIGluIGNvdmVyYWdlIGZpbGUgJiBzZWdtZW50IHNpemUgaW5mb3JtYXRpb24KYGBge3J9CmNvdiA9IHJlYWQuY3N2KCIuL2F2Z19jb3ZlcmFnZS9IOU4yLmNvdmVyYWdlLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIikKCnNlZ19zaXplcyA9ICIuLi9TZWdtZW50U2l6ZS5jc3YiCnNpemVzID0gcmVhZC5jc3YoZmlsZT1zZWdfc2l6ZXMsaGVhZGVyPVQsc2VwPSIsIixuYS5zdHJpbmdzID0gYygnJykpCkdlbm9tZVNpemUgPSAoc2l6ZXMgJT4lIGZpbHRlcihzZWdtZW50ID09ICdIOU4yX0dFTk9NRScpKSRTZWdtZW50U2l6ZQoKY292JHNlZ21lbnQgPSBmYWN0b3IoY292JHNlZ21lbnQsIGxldmVscyA9IFNFR01FTlRTKQpgYGAKCkNoZWNraW5nIGlmIGRhdGEgcGFzc2VzIHRocmVzaG9sZHMKYGBge3J9CmNvdl9jaGVjayA9IENvdmVyYWdlQWNyb3NzKGNvdixjb3ZfY3V0LDQwLHNpemVzLCB3a2RpcikKYGBgCgpNZXJnaW5nIGNvdmVyYWdlIGNoZWNrIGluZm8gd2l0aCB0aGUgcmVzdCBvZiB0aGUgbWV0YWRhdGEKYGBge3J9Cm1ldGEgPSBtZXJnZShtZXRhLCBjb3ZfY2hlY2ssIGJ5LnggPSBjKCJzYW1wbGUiKSwgYnkueSA9IGMoIm5hbWUiKSwgYWxsLnkgPSBUUlVFKQoKbnJvdyhtZXRhKQpjb3VudChtZXRhLHF1YWxpdHkpCmBgYAoKTG9hZGluZyBpbiB2YXJpYW50IGZpbGVzCmBgYHtyfQp2YXJmaWxlID0gIi4vdmFyZmlsZXMvSDlOMi5WYXJpYW50c09ubHkuMC4wMS4yMDAuY3N2IgoKIyByZWFkIGFuZCByZWFycmFuZ2UgdGhlIGRhdGEKdmFycyA9IHJlYWQuY3N2KGZpbGU9dmFyZmlsZSxoZWFkZXI9VCxzZXA9IiwiLG5hLnN0cmluZ3MgPSBjKCcnKSkKdmFycyRuYW1lID0gdmFycyRzYW1wbGUKYGBgCgpSZWFycmFuZ2luZyB2YXJpYW50IGRhdGFmcmFtZQpgYGB7cn0KdmRmID0gQXJyYW5nZVZhcldSZXAodmFycykKIyBhbHJlYWR5IGhhdmUgcmVwbGljYXRlIGRhdGEgaW4gdGhlIHZhcmZpbGVzIGZyb20gcnVubmluZyBDb21wYXJlUmVwcy52Mi5weSBzY3JpcHQKdmRmID0gdmRmWyFkdXBsaWNhdGVkKHZkZiksIF0gJT4lIGRyb3BsZXZlbHMoKQpucm93KHZkZikKYGBgCgpGaWx0ZXJpbmcgdmFyaWFudCBkZiBieSB0aW1vIGJpbm9jaGVjawpgYGB7cn0KdmRmJGJpbm9jaGVjayA9IGZhY3Rvcih2ZGYkYmlub2NoZWNrLCBsZXZlbHMgPSBjKCJGYWxzZSIsIlIxIiwiUjIiLCJUcnVlIikpCnZkZl9iaW5vID0gZmlsdGVyKHZkZiwgYmlub2NoZWNrICE9ICJGYWxzZSIpCnZkZl9iaW5vID0gdmRmX2Jpbm9bIWR1cGxpY2F0ZWQodmRmX2Jpbm8pLCBdICU+JSBkcm9wbGV2ZWxzKCkKbnJvdyh2ZGZfYmlubykKIyB0aGlzIHJlYWxseSBnZXRzIHJpZCBvZiBhIGxvdCBvZiB2YXJpYW50cyAofjEwMDApCmBgYAoKRmlsdGVyaW5nIHZhcmlhbnQgZGYgd2l0aCBmcmVxdWVuY3kgY3V0b2ZmcwpgYGB7cn0KdmRmID0gZmlsdGVyKHZkZiwgbWlub3JmcmVxMSA+PSBmcmVxX2N1dCAmIAogICAgICAgICAgICAgICBtaW5vcmZyZXEyID49IGZyZXFfY3V0ICYgCiAgICAgICAgICAgICAgIG1pbm9yICVpbiUgbnRsaXN0ICYKICAgICAgICAgICAgICAgbWFqb3IgJWluJSBudGxpc3QpICU+JSAKICAgICAgICAgICAgZHJvcGxldmVscygpCiMgYmFzZWQgb24gTUFGIHN0dWR5LCByZXBzIGFuZCAwLjAxJSBjdXRvZmYgd2FzIGJlc3QgY29tYm8KI2ZpbHRlciBlYWNoIHJlcGxpY2F0ZSBzZXBhcmF0ZWx5IHJhdGhlciB0aGFuIHVzaW5nIHRoZSBhdmVyYWdlCgp2ZGYgPSB2ZGZbIWR1cGxpY2F0ZWQodmRmKSwgXSAlPiUgZHJvcGxldmVscygpCm5yb3codmRmKQojIGRvZXMgbm90IGVsaW1pbmF0ZSBhbnkgdmFyaWFudHMgaGVyZQpgYGAKCkFkZGluZyBtZXRhZGF0YQpgYGB7cn0KdmRmID0gbWVyZ2UodmRmLG1ldGEsIGJ5ID0gYygic2FtcGxlIiwic2VnbWVudCIpKQp2ZGYgPSB2ZGZbIWR1cGxpY2F0ZWQodmRmKSwgXSAlPiUgZHJvcGxldmVscygpCgp2ZGYkc2VnbWVudCA9IGZhY3Rvcih2ZGYkc2VnbWVudCwgbGV2ZWxzID0gU0VHTUVOVFMpCgp2ZGYgPSBmaWx0ZXIodmRmLCBpbmZfcm91dGUgPT0gIkluZGV4IiB8IGluZl9yb3V0ZSA9PSAiQ29udGFjdCIgfCBpbmZfcm91dGUgPT0gIkNvbnRyb2wiKQojIGlnbm9yaW5nIGFlcm9zb2wgZm9yIG5vdwpgYGAKCmBgYHtyfQp2ZGYgPSBmaWx0ZXIodmRmLCBxdWFsaXR5ID09ICJnb29kIikKdmRmID0gdmRmWyFkdXBsaWNhdGVkKHZkZiksIF0gJT4lIGRyb3BsZXZlbHMoKQoKZ29vZF9uYW1lcyA9IGMobGV2ZWxzKGZhY3Rvcih2ZGYkc2FtcGxlKSkpCmBgYAoKYGBge3J9CnRyYW5zbWlzc2lvbl9pbmZvID0gIi9Vc2Vycy9tYXJpc3Nha25vbGwvRGVza3RvcC9HaXRIdWIvT2Jlc2l0eS9OZXdFeHRyYWN0aW9ucy9IOU4yL1RyYW5zbWlzc2lvblBhaXJzLmNzdiIKcGFpcnMgPSByZWFkLmNzdih0cmFuc21pc3Npb25faW5mbywgaGVhZGVyID0gVCkKYGBgCgpgYGB7cn0KY29uX2NoYW5nZSA9IGZpbHRlcih2ZGYsIHN0b2NrbnQgIT0gbWFqb3IpICU+JQogIGZpbHRlcihtYWpvciAlaW4lIG50bGlzdCkKY29uX2NoYW5nZSA9IGNvbl9jaGFuZ2VbIWR1cGxpY2F0ZWQoY29uX2NoYW5nZSksIF0KY29uX2NoYW5nZSRudHZhciA9IHBhc3RlMChjb25fY2hhbmdlJGZlcnJldElELCJfIixjb25fY2hhbmdlJHNlZ21lbnQsIl8iLAogICAgICAgICAgICAgICAgICAgICAgICBjb25fY2hhbmdlJG1ham9yLCJfIixjb25fY2hhbmdlJG50cG9zLCJfIixjb25fY2hhbmdlJG1pbm9yKQpjb25zZW5zdXMgPSB1bmlxdWUoY29uX2NoYW5nZSRudHZhcikKbGVuZ3RoKGNvbnNlbnN1cykKYGBgCgpgYGB7cn0KdmRmJG50dmFyID0gcGFzdGUwKHZkZiRmZXJyZXRJRCwiXyIsdmRmJHNlZ21lbnQsIl8iLHZkZiRtYWpvciwiXyIsdmRmJG50cG9zLCJfIix2ZGYkbWlub3IpCgptaW5vcnZkZiA9IGZpbHRlcih2ZGYsICEobnR2YXIgJWluJSBjb25zZW5zdXMpKSAlPiUgdW5pcXVlKCkKbnJvdyh2ZGYpIC0gbnJvdyhtaW5vcnZkZikKYGBgCgpTTlYgbG9jYXRpb24gcGxvdHMKYGBge3J9ClNOVkxvY2F0aW9uID0gZ2dwbG90KG1pbm9ydmRmLCBhZXMoeCA9IG50cG9zLCB5ID0gZmVycmV0SUQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkaWV0LCBzaGFwZSA9IGNvaG9ydCkpICsKICBmYWNldF9ncmlkKGluZl9yb3V0ZX5zZWdtZW50KSArCiAgUGxvdFRoZW1lMSArCiAgRGlldGNvbFNjYWxlCnByaW50KFNOVkxvY2F0aW9uKQpnZ3NhdmUoU05WTG9jYXRpb24sIGZpbGUgPSAiU05WTG9jYXRpb24ucGRmIiwgcGF0aCA9IHNhdmVkaXIpCiMgZmVycmV0IDE3ODcgZG9lc24ndCBoYXZlIGFueSB2YXJpYW50cz8/CmBgYAoKYGBge3J9Cm1pbm9ydmRmJG50dmFyID0gcGFzdGUwKG1pbm9ydmRmJHNlZ21lbnQsIl8iLG1pbm9ydmRmJG1ham9yLG1pbm9ydmRmJG50cG9zLG1pbm9ydmRmJG1pbm9yKQoKIyBDb21wYXJpbmcgdG8gU05WcyBmb3VuZCBpbiB0aGUgc3RvY2sKCkYxN19zdG9jayA9IGZpbHRlcihtaW5vcnZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiRjE3IikgCkYxN19zdG9ja19udHZhciA9IHVuaXF1ZShGMTdfc3RvY2skbnR2YXIpClcxN19zdG9jayA9IGZpbHRlcihtaW5vcnZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiVzE3IikKVzE3X3N0b2NrX250dmFyID0gdW5pcXVlKFcxN19zdG9jayRudHZhcikKU20xOF9zdG9jayA9IGZpbHRlcihtaW5vcnZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiU20xOCIpClNtMThfc3RvY2tfbnR2YXIgPSB1bmlxdWUoU20xOF9zdG9jayRudHZhcikKU3AxOV9zdG9jayA9IGZpbHRlcihtaW5vcnZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiU3AxOSIpClNwMTlfc3RvY2tfbnR2YXIgPSB1bmlxdWUoU3AxOV9zdG9jayRudHZhcikKU3AyMF9zdG9jayA9IGZpbHRlcihtaW5vcnZkZiwgRFBJID09ICJTdG9jayIsIGNvaG9ydCA9PSAiU3AyMCIpClNwMjBfc3RvY2tfbnR2YXIgPSB1bmlxdWUoU3AyMF9zdG9jayRudHZhcikKCkYxN19mZXJyZXQgPSBmaWx0ZXIobWlub3J2ZGYgLCBjb2hvcnQgPT0gIkYxNyIsIGluZl9yb3V0ZSAhPSAiQ29udHJvbCIpCkYxN19mZXJyZXRfbnR2YXIgPSB1bmlxdWUoRjE3X2ZlcnJldCRudHZhcikKVzE3X2ZlcnJldCA9IGZpbHRlcihtaW5vcnZkZiAsY29ob3J0ID09ICJXMTciLCBpbmZfcm91dGUgIT0gIkNvbnRyb2wiKQpXMTdfZmVycmV0X250dmFyID0gdW5pcXVlKFcxN19mZXJyZXQkbnR2YXIpClNtMThfZmVycmV0ID0gZmlsdGVyKG1pbm9ydmRmICxjb2hvcnQgPT0gIlNtMTgiLCBpbmZfcm91dGUgIT0gIkNvbnRyb2wiKQpTbTE4X2ZlcnJldF9udHZhciA9IHVuaXF1ZShTbTE4X2ZlcnJldCRudHZhcikKU3AxOV9mZXJyZXQgPSBmaWx0ZXIobWlub3J2ZGYgLGNvaG9ydCA9PSAiU3AxOSIsIGluZl9yb3V0ZSAhPSAiQ29udHJvbCIpClNwMTlfZmVycmV0X250dmFyID0gdW5pcXVlKFNwMTlfZmVycmV0JG50dmFyKQpTcDIwX2ZlcnJldCA9IGZpbHRlcihtaW5vcnZkZiAsY29ob3J0ID09ICJTcDIwIiwgaW5mX3JvdXRlICE9ICJDb250cm9sIikKU3AyMF9mZXJyZXRfbnR2YXIgPSB1bmlxdWUoU3AyMF9mZXJyZXQkbnR2YXIpCmBgYAoKYGBge3J9CkYxN19zaGFyZWQgPSBGMTdfZmVycmV0ICU+JSBmaWx0ZXIobnR2YXIgJWluJSBGMTdfc3RvY2tfbnR2YXIpICU+JSBmaWx0ZXIoKG50dmFyICVpbiUgRjE3X2ZlcnJldF9udHZhcikpICU+JSB1bmlxdWUoKQpGMTdfZGVub3ZvID0gRjE3X2ZlcnJldCAlPiUgZmlsdGVyKChudHZhciAlaW4lIEYxN19mZXJyZXRfbnR2YXIpKSAlPiUgZmlsdGVyKCEobnR2YXIgJWluJSBGMTdfc3RvY2tfbnR2YXIpKSAlPiUgdW5pcXVlKCkKClcxN19zaGFyZWQgPSBXMTdfZmVycmV0ICU+JSBmaWx0ZXIobnR2YXIgJWluJSBXMTdfc3RvY2tfbnR2YXIpICU+JSBmaWx0ZXIoKG50dmFyICVpbiUgVzE3X2ZlcnJldF9udHZhcikpICU+JSB1bmlxdWUoKQpXMTdfZGVub3ZvID0gVzE3X2ZlcnJldCAlPiUgZmlsdGVyKChudHZhciAlaW4lIFcxN19mZXJyZXRfbnR2YXIpKSAlPiUgZmlsdGVyKCEobnR2YXIgJWluJSBXMTdfc3RvY2tfbnR2YXIpKSAlPiUgdW5pcXVlKCkKClNtMThfc2hhcmVkID0gU20xOF9mZXJyZXQgJT4lIGZpbHRlcihudHZhciAlaW4lIFNtMThfc3RvY2tfbnR2YXIpICU+JSBmaWx0ZXIoKG50dmFyICVpbiUgU20xOF9mZXJyZXRfbnR2YXIpKSAlPiUgdW5pcXVlKCkKU20xOF9kZW5vdm8gPSBTbTE4X2ZlcnJldCAlPiUgZmlsdGVyKChudHZhciAlaW4lIFNtMThfZmVycmV0X250dmFyKSkgJT4lIGZpbHRlcighKG50dmFyICVpbiUgU20xOF9zdG9ja19udHZhcikpICU+JSB1bmlxdWUoKQoKU3AxOV9zaGFyZWQgPSBTcDE5X2ZlcnJldCAlPiUgZmlsdGVyKG50dmFyICVpbiUgU3AxOV9zdG9ja19udHZhcikgJT4lIGZpbHRlcigobnR2YXIgJWluJSBTcDE5X2ZlcnJldF9udHZhcikpICU+JSB1bmlxdWUoKQpTcDE5X2Rlbm92byA9IFNwMTlfZmVycmV0ICU+JSBmaWx0ZXIoKG50dmFyICVpbiUgU3AxOV9mZXJyZXRfbnR2YXIpKSAlPiUgZmlsdGVyKCEobnR2YXIgJWluJSBTcDE5X3N0b2NrX250dmFyKSkgJT4lIHVuaXF1ZSgpCgpTcDIwX3NoYXJlZCA9IFNwMjBfZmVycmV0ICU+JSBmaWx0ZXIobnR2YXIgJWluJSBTcDIwX3N0b2NrX250dmFyKSAlPiUgZmlsdGVyKChudHZhciAlaW4lIFNwMjBfZmVycmV0X250dmFyKSkgJT4lIHVuaXF1ZSgpClNwMjBfZGVub3ZvID0gU3AyMF9mZXJyZXQgJT4lIGZpbHRlcigobnR2YXIgJWluJSBTcDIwX2ZlcnJldF9udHZhcikpICU+JSBmaWx0ZXIoIShudHZhciAlaW4lIFNwMjBfc3RvY2tfbnR2YXIpKSAlPiUgdW5pcXVlKCkKYGBgCgpgYGB7cn0Kc3RvY2tfc2hhcmVkID0gcmJpbmQoRjE3X3NoYXJlZCwgVzE3X3NoYXJlZCwgU20xOF9zaGFyZWQsIFNwMTlfc2hhcmVkLCBTcDIwX3NoYXJlZCkKc3RvY2tfc2hhcmVkJGFhdmFyID0gcGFzdGUwKHN0b2NrX3NoYXJlZCRtYWpvcmFhLHN0b2NrX3NoYXJlZCRhYXBvcyxzdG9ja19zaGFyZWQkbWlub3JhYSkKCmZlcnVuaXF1ZSA9IHJiaW5kKEYxN19kZW5vdm8sIFcxN19kZW5vdm8sIFNtMThfZGVub3ZvLCBTcDE5X2Rlbm92bywgU3AyMF9kZW5vdm8pCmZlcnVuaXF1ZSRhYXZhciA9IHBhc3RlMChmZXJ1bmlxdWUkbWFqb3JhYSxmZXJ1bmlxdWUkYWFwb3MsZmVydW5pcXVlJG1pbm9yYWEpCmBgYAoKU05WIExvY2F0aW9uIGNvbXBhcmVkIHRvIHN0b2NrCmBgYHtyfQpTdG9ja1NoYXJlZFBsb3QgPSBnZ3Bsb3Qoc3RvY2tfc2hhcmVkLCBhZXMoeCA9IG50cG9zLCB5ID0gZmVycmV0SUQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkaWV0LCBzaGFwZSA9IGNvaG9ydCksIHNpemUgPSAyKSArCiAgZmFjZXRfZ3JpZChpbmZfcm91dGV+c2VnbWVudCwgZHJvcCA9IEZBTFNFKSArCiAgUGxvdFRoZW1lMSArCiAgRGlldGNvbFNjYWxlICsKICBnZ3RpdGxlKCJTTlZzIGZvdW5kIGluIHN0b2NrIikKcHJpbnQoU3RvY2tTaGFyZWRQbG90KQpnZ3NhdmUoU3RvY2tTaGFyZWRQbG90LCBmaWxlID0gIlN0b2NrU2hhcmVkUGxvdC5wZGYiLCBoZWlnaHQgPSAzMCwgd2lkdGggPSAxNSwgcGF0aCA9IHNhdmVkaXIpCgpGZXJVbmlxdWVQbG90ID0gZ2dwbG90KGZlcnVuaXF1ZSwgYWVzKHggPSBudHBvcywgeSA9IGZlcnJldElEKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGlldCkpICsKICBmYWNldF9ncmlkKGluZl9yb3V0ZX5zZWdtZW50KSArCiAgUGxvdFRoZW1lMSArCiAgRGlldGNvbFNjYWxlICsKICBnZ3RpdGxlKCJTTlZzIG5vdCBmb3VuZCBpbiBzdG9jayIpCnByaW50KEZlclVuaXF1ZVBsb3QpCmdnc2F2ZShGZXJVbmlxdWVQbG90LCBmaWxlID0gIkZlclVuaXF1ZVBsb3QucGRmIiwgcGF0aCA9IHNhdmVkaXIpCmBgYAoKVmVubiBkaWFncmFtIG9mIG9iZXNlIGFuZCBsZWFuIGRlIG5vdm8gU05WcwpgYGB7cn0Kb192YXIgPSBmaWx0ZXIoZmVydW5pcXVlLCBkaWV0ID09ICJPYmVzZSIpIApvX3ZhciA9IHVuaXF1ZShvX3ZhciRudHZhcikKCmxfdmFyID0gZmlsdGVyKGZlcnVuaXF1ZSwgZGlldCA9PSAiTGVhbiIpIApsX3ZhciA9IHVuaXF1ZShsX3ZhciRudHZhcikKCmRpZXRfdmFyIDwtIGxpc3QoT2Jlc2UgPSBvX3ZhciwgTGVhbiA9IGxfdmFyKQoKRGlldFVuaXF1ZVNOVlMgPSBnZ1Zlbm5EaWFncmFtKGRpZXRfdmFyKQpwcmludChEaWV0VW5pcXVlU05WUykKZ2dzYXZlKERpZXRVbmlxdWVTTlZTLCBmaWxlID0gIkRpZXRVbmlxdWVTTlZTLnBkZiIsIHBhdGggPSBzYXZlZGlyKQpgYGAKCk9iZXNlLSBhbmQgbGVhbi1zcGVjaWZpYyBTTlZzCmBgYHtyfQpsZWFuID0gZmVydW5pcXVlICU+JSAKICBmaWx0ZXIobnR2YXIgJWluJSBsX3ZhcikgJT4lIAogIGZpbHRlcighKG50dmFyICVpbiUgb192YXIpKSAlPiUgCiAgdW5pcXVlKCkKCmxlYW4kZmVycmV0SURfdmFyID0gcGFzdGUwKGxlYW4kZmVycmV0SUQsIl8iLGxlYW4kbnR2YXIpCgpyZXBlYXRzX2xlYW4gPSBsZWFuICU+JSAKICBncm91cF9ieShudHZhcixmZXJyZXRJRCkgJT4lIAogIHRhbGx5KCkgJT4lCiAgZ3JvdXBfYnkobnR2YXIpICU+JQogIHRhbGx5KCkgJT4lIHVuaXF1ZSgpCgpsZWFuID0gbWVyZ2UobGVhbiwgcmVwZWF0c19sZWFuLCBieSA9IGMoIm50dmFyIikpICU+JSB1bmlxdWUoKQoKb2Jlc2UgPSBmZXJ1bmlxdWUgJT4lIAogIGZpbHRlcihudHZhciAlaW4lIG9fdmFyKSAlPiUgCiAgZmlsdGVyKCEobnR2YXIgJWluJSBsX3ZhcikpICU+JQogIHVuaXF1ZSgpCgpvYmVzZSRmZXJyZXRJRF92YXIgPSBwYXN0ZTAob2Jlc2UkZmVycmV0SUQsIl8iLG9iZXNlJG50dmFyKQoKcmVwZWF0c19vYmVzZSA9IG9iZXNlICU+JSAKICBncm91cF9ieShudHZhcixmZXJyZXRJRCkgJT4lIAogIHRhbGx5KCkgJT4lCiAgZ3JvdXBfYnkobnR2YXIpICU+JQogIHRhbGx5KCkgJT4lCiAgdW5pcXVlKCkKCm9iZXNlID0gbWVyZ2Uob2Jlc2UsIHJlcGVhdHNfb2Jlc2UsIGJ5ID0gYygibnR2YXIiKSkgJT4lIHVuaXF1ZSgpCmBgYAoKRGV0ZXJtaW5pbmcgaWYgZGlldC11bmlxdWUgc2hhcmVkIHZhcmlhbnRzIGFyZSB0cmFuc21pdHRlZApgYGB7cn0KZGlldHVuaXF1ZSA9IHJiaW5kKGxlYW4sb2Jlc2UpICU+JSB1bmlxdWUoKQpkaWV0dW5pcXVlID0gbWVyZ2UoZGlldHVuaXF1ZSwgcGFpcnMsIGJ5ID0gYygiZmVycmV0SUQiKSkKCnNoYXJlZCA9IGZpbHRlcihkaWV0dW5pcXVlLCBuID09IDIpCnQgPSB1bmlxdWUoc2hhcmVkJG50dmFyKQoKdHJhbnNtaXR0ZWQgPSBkYXRhLmZyYW1lKCkKCmZvcihpIGluIHQpewogIHByaW50KGkpCiAgZGYgPSBmaWx0ZXIoc2hhcmVkLCBudHZhciA9PSBpKQogIGRmMSA9IGdyb3VwX2J5KGRmLHBhaXJfbnVtYmVycykgJT4lIHRhbGx5KCkKICAjIGhlcmUgYSAyIG1lYW5zIHRoYXQgdGhlIHR3byBmZXJyZXRzIGFyZSBpbiB0aGUgc2FtZSB0cmFuc21pc3Npb24gcGFpciBhbmQgYSAxIGluZGljYXRlcyBkaWZmZXJlbnQgdHJhbnNtaXNzaW9uIHBhaXJzCiAgZGYyID0gbWVyZ2UoZGYsIGRmMSwgYnkgPSBjKCJwYWlyX251bWJlcnMiKSkKICAjIGFkZCB0aGlzIGluZm9ybWF0aW9uIGJhY2sgaW50byB0aGUgZGF0YWZyYW1lCiAgZGYyJHRyYW5zbWlzc2lvbiA9IGRmMiRuLnkKICB0cmFuc21pdHRlZCA9IHJiaW5kKHRyYW5zbWl0dGVkLCBkZjIpCn0KCiNmb3JtYXR0aW5nIHN0dWZmCm5vdHNoYXJlZCA9IGZpbHRlcihkaWV0dW5pcXVlLCBuID09IDEpCm5vdHNoYXJlZCR0cmFuc21pc3Npb24gPSAwCnRyYW5zbWl0dGVkJG4gPSB0cmFuc21pdHRlZCRuLngKdHJhbnNtaXR0ZWQgPSB0cmFuc21pdHRlZCAlPiUgc2VsZWN0KCEobi54KSkgJT4lIHNlbGVjdCghKG4ueSkpCgpkaWV0dW5pcXVlID0gcmJpbmQobm90c2hhcmVkLCB0cmFuc21pdHRlZCkKZGlldHVuaXF1ZSR0cmFuc21pc3Npb24gPSBhcy5jaGFyYWN0ZXIoZGlldHVuaXF1ZSR0cmFuc21pc3Npb24pCmBgYAoKYGBge3J9CkRpZXRVbmlxdWUgPSBnZ3Bsb3QoZGlldHVuaXF1ZSwgYWVzKHggPSBudHBvcywgeSA9IHNlZ21lbnQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBub25zeW4sIHNpemUgPSBuLCBzaGFwZSA9IHRyYW5zbWlzc2lvbikpICsgCiAgZ2d0aXRsZSgiTnVtYmVyIG9mIHNhbXBsZXMgY29udGFpbmluZyBlYWNoIHZhcmlhbnQgLSBkaWV0IHNwZWNpZmljIikgKwogIHRoZW1lKGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIiksCiAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKwogIGZhY2V0X2dyaWQoZGlldH5TVFJBSU4pICsKICBQbG90VGhlbWUxCnByaW50KERpZXRVbmlxdWUpCiNnZ3NhdmUoRGlldFVuaXF1ZSwgZmlsZW5hbWUgPSAiU2VnbWVudFNOVlBsb3RfRGlldFVucWlxdWUucGRmIiwgcGF0aCA9IHNhdmVkaXIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpCmBgYAoKYGBge3J9CiMgbWFrZSBuZXcgdmVyc2lvbiBvZiB0aGlzIGZpZ3VyZSwgc2VwYXJhdGluZyBvdXQgdHJhbnNtaXNzaW9uIHYgaW5kZXBlbmRlbnQgZmVycmV0cwpEaWV0VW5pcXVlID0gZ2dwbG90KGZpbHRlcihkaWV0dW5pcXVlKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBudHBvcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBmYWN0b3Ioc2VnbWVudCwgbGV2ZWxzID0gYygnSDlOMl9OUycsJ0g5TjJfTVAnLCdIOU4yX05BJywnSDlOMl9OUCcsJ0g5TjJfSEEnLCdIOU4yX1BBJywnSDlOMl9QQjEnLCdIOU4yX1BCMicpKSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IG5vbnN5biwgc2l6ZSA9IG4pKSArIAogIGdndGl0bGUoIk51bWJlciBvZiBzYW1wbGVzIGNvbnRhaW5pbmcgZWFjaCB2YXJpYW50IC0gZGlldCBzcGVjaWZpYyIpICsKICB4bGFiKCJOdWNsZW90aWRlIHBvc2l0aW9uIikgKwogIHlsYWIoIlNlZ21lbnQiKSArCiAgUGxvdFRoZW1lMQpwcmludChEaWV0VW5pcXVlKQpnZ3NhdmUoRGlldFVuaXF1ZSwgZmlsZW5hbWUgPSAiU2VnbWVudFNOVlBsb3RfRGlldFVucWlxdWUucGRmIiwgcGF0aCA9IHNhdmVkaXIsIHdpZHRoID0gMTUsIGhlaWdodCA9IDEwKQoKCkRpZXRVbmlxdWVfVHJhbnNtaXNzaW9uID0gZ2dwbG90KGZpbHRlcihkaWV0dW5pcXVlLCBuID4gMSwgbm9uc3luICE9ICJzeW4iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBudHBvcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBmYWN0b3Ioc2VnbWVudCwgbGV2ZWxzID0gYygnSDlOMl9OUycsJ0g5TjJfTVAnLCdIOU4yX05BJywnSDlOMl9OUCcsJ0g5TjJfSEEnLCdIOU4yX1BBJywnSDlOMl9QQjEnLCdIOU4yX1BCMicpKSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHRyYW5zbWlzc2lvbiwgc2l6ZSA9IDIsIHNoYXBlID0gdHJhbnNtaXNzaW9uKSkgKyAKICBnZ3RpdGxlKCJOdW1iZXIgb2Ygc2FtcGxlcyBjb250YWluaW5nIGVhY2ggdmFyaWFudCAtIGRpZXQgc3BlY2lmaWMiKSArCiAgeGxhYigiTnVjbGVvdGlkZSBwb3NpdGlvbiIpICsKICB5bGFiKCJTZWdtZW50IikgKwogIGZhY2V0X2dyaWQoZGlldH5pbmZfcm91dGUpICsKICBQbG90VGhlbWUxCnByaW50KERpZXRVbmlxdWVfVHJhbnNtaXNzaW9uKQpnZ3NhdmUoRGlldFVuaXF1ZV9UcmFuc21pc3Npb24sIGZpbGUgPSAiRGlldFVuaXF1ZV9UcmFuc21pc3Npb24ucGRmIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA1LCBwYXRoID0gc2F2ZWRpcikKYGBgCgpQdWxsaW5nIG91dCByZXBlYXRlZCBub25zeW5vbnltb3VzIG11dGF0aW9ucwpgYGB7cn0Kbm9uc3lucyA9IGZpbHRlcihkaWV0dW5pcXVlLCBub25zeW4gPT0gIm5vbnN5biIgJiBuID4gMSkgJT4lIHVuZ3JvdXAoKSAlPiUgdW5pcXVlKCkgJT4lIGRyb3BsZXZlbHMoKSAKbm9uc3luc19zbW9sID0gc2VsZWN0KG5vbnN5bnMsbnR2YXIsYWF2YXIsZGlldCxpbmZfcm91dGUsbikgJT4lIGRyb3BsZXZlbHMoKQp3cml0ZS5jc3Yobm9uc3luc19zbW9sLCAibm9uc3lucy5jc3YiKQoKbm9uc3luc19kaWV0dW5pcXVlID0gZmlsdGVyKGRpZXR1bmlxdWUsIG5vbnN5biA9PSAibm9uc3luIiAmIG4gPiAxKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBzZWxlY3QoZGlldCxudHZhcixhYXZhcixuKSAlPiUKICB1bmlxdWUoKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCgp3cml0ZS50YWJsZShub25zeW5zX2RpZXR1bmlxdWUsICJub25zeW5zX2RpZXR1bmlxdWUuY3N2Iiwgc2VwID0gIiwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpkTmRTIGFuYWx5c2lzIG9mIGRlIG5vdm8sIGRpZXQgdW5pcXVlIGdlbmVzCmBgYHtyfQojIGJ5IGZlcnJldApkTmRTX2Rlbm92b19mZXJyZXQgPSBkaWV0dW5pcXVlICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdyb3VwX2J5KGZlcnJldElELERQSSxkaWV0LGluZl9yb3V0ZSkgJT4lIAogIGNvdW50KG5vbnN5bikKCmROZFNfZGVub3ZvX2ZlcnJldCA9IHBpdm90X3dpZGVyKGROZFNfZGVub3ZvX2ZlcnJldCxuYW1lc19mcm9tID0gbm9uc3luLCB2YWx1ZXNfZnJvbSA9IG4pCmROZFNfZGVub3ZvX2ZlcnJldCA9IHNlbGVjdChkTmRTX2Rlbm92b19mZXJyZXQsIGZlcnJldElELERQSSxub25zeW4sc3luKQpkTmRTX2Rlbm92b19mZXJyZXQkZE5kUyA9IHBhc3RlMChkTmRTX2Rlbm92b19mZXJyZXQkbm9uc3luIC8gZE5kU19kZW5vdm9fZmVycmV0JHN5bikKZE5kU19kZW5vdm9fZmVycmV0JGROZFMgPSBhcy5udW1lcmljKGROZFNfZGVub3ZvX2ZlcnJldCRkTmRTKQoKZE5kU19kZW5vdm9fZmVycmV0X3Bsb3QgPSBnZ3Bsb3QoZE5kU19kZW5vdm9fZmVycmV0LCBhZXMoeCA9IERQSSwgeSA9IGROZFMsIGNvbG9yID0gZmVycmV0SUQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gZmVycmV0SUQpKSArCiAgZmFjZXRfZ3JpZCh+ZGlldCtpbmZfcm91dGUpICsKICBQbG90VGhlbWUxIApwcmludChkTmRTX2Rlbm92b19mZXJyZXRfcGxvdCkKZ2dzYXZlKCJkTmRTX2Rlbm92b19mZXJyZXQucGRmIiwgZE5kU19kZW5vdm9fZmVycmV0X3Bsb3QsIHBhdGggPSBzYXZlZGlyKQpgYGAKCgpXaGljaCBmZXJyZXRzIGhhdmUgbW9yZSB0aGFuIG9uZSBkZSBub3ZvPwpgYGB7cn0KZ2dwbG90KGRpZXR1bmlxdWUsIGFlcyh4ID0gbnRwb3MsIHkgPSBmZXJyZXRJRCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRpZXQpKSArCiAgZmFjZXRfZ3JpZCh+c2VnbWVudCkgKwogIFBsb3RUaGVtZTEgKwogIERpZXRjb2xTY2FsZQoKZ2dwbG90KGZpbHRlcihkaWV0dW5pcXVlLCBuID4xKSwgYWVzKHggPSBudHBvcywgeSA9IGZlcnJldElEKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGlldCkpICsKICBmYWNldF9ncmlkKH5zZWdtZW50KSArCiAgUGxvdFRoZW1lMSArCiAgRGlldGNvbFNjYWxlCmBgYApTTlZzIHNoYXJlZCBiZXR3ZWVuIGRpZXQgZ3JvdXBzCmBgYHtyfQpzaGFyZWQgPSBmZXJ1bmlxdWUgJT4lIAogIGZpbHRlcihudHZhciAlaW4lIG9fdmFyKSAlPiUgCiAgZmlsdGVyKG50dmFyICVpbiUgbF92YXIpICU+JSAKICB1bmlxdWUoKQpzaGFyZWQkZmVycmV0SURfdmFyID0gcGFzdGUwKHNoYXJlZCRmZXJyZXRJRCwiXyIsc2hhcmVkJG50dmFyKQoKcmVwZWF0c19zaGFyZWQgPSBzaGFyZWQgJT4lIAogIGdyb3VwX2J5KG50dmFyLGZlcnJldElEKSAlPiUgCiAgdGFsbHkoKSAlPiUKICBncm91cF9ieShudHZhcikgJT4lCiAgdGFsbHkoKQojIHRoaXMgaXMgdG8gbWFrZSBzdXJlIEknbSBub3QgcmVwZWF0ZWRseSBjb3VudGluZyBhIHZhcmlhbnQgZm91bmQgaW4gb25lIGZlcnJldCBidXQgbXVsdGlwbGUgZGF5cyAKCnNoYXJlZCA9IG1lcmdlKHNoYXJlZCwgcmVwZWF0c19zaGFyZWQsIGJ5ID0gYygibnR2YXIiKSkKClNoYXJlZFBsb3QgPSBnZ3Bsb3Qoc2hhcmVkLCAKICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IG50cG9zLAogICAgICAgICAgICAgICAgICAgICAgICB5ID0gZmFjdG9yKHNlZ21lbnQsIGxldmVscyA9IGMoJ0g5TjJfTlMnLCdIOU4yX01QJywnSDlOMl9OQScsJ0g5TjJfTlAnLCdIOU4yX0hBJywnSDlOMl9QQScsJ0g5TjJfUEIxJywnSDlOMl9QQjInKSkpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IG4sIGNvbG9yID0gbm9uc3luKSkgKwogIGdndGl0bGUoIk51bWJlciBvZiBzYW1wbGVzIGNvbnRhaW5pbmcgZWFjaCB2YXJpYW50IC0gU2hhcmVkIGJldHdlZW4gZGlldCBncm91cHMiKSArCiAgdGhlbWUobGVnZW5kLmtleSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXI9ImJsYWNrIiwgZmlsbD0id2hpdGUiKSwKICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpKSArCiAgeGxhYigiTnVjbGVvdGlkZSBwb3NpdGlvbiIpICsKICB5bGFiKCJTZWdtZW50IikgKwogIFBsb3RUaGVtZTEKcHJpbnQoU2hhcmVkUGxvdCkKZ2dzYXZlKFNoYXJlZFBsb3QsIGZpbGVuYW1lID0gIlNlZ21lbnRTTlZQbG90X0RpZXRTaGFyZWQucGRmIiwgcGF0aCA9IHNhdmVkaXIpCmBgYAoKRXh0cmFjdGluZyBjb21tb24gbm9uc3lub255bW91cyB2YXJpYW50cyBzaGFyZWQgYmV0d2VlbiBkaWV0IGdyb3VwcwpgYGB7cn0Kbm9uc3luc19zaGFyZWQgPSBmaWx0ZXIoc2hhcmVkLCBub25zeW4gPT0gIm5vbnN5biIgJiBuID4gMSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KG50dmFyLGFhdmFyLG4pICU+JQogIHVuaXF1ZSgpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkKCndyaXRlLnRhYmxlKG5vbnN5bnNfc2hhcmVkLCAibm9uc3luc19zaGFyZWQuY3N2Iiwgc2VwID0gIiwiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpJcyB0aGVyZSBhIGRpZmZlcmVuY2UgaW4gaG93IG9mdGVuIHRoZXNlIHZhcmlhbnRzIGFyZSBmb3VuZCBpbiBvYmVzZSB2IGxlYW4gZmVycmV0cz8KYGBge3J9CnNoYXJlZF92YXJzID0gZ3JvdXBfYnkoc2hhcmVkLCBudHZhciwgZGlldCkgJT4lIHRhbGx5KCkgCgpnZ3Bsb3Qoc2hhcmVkX3ZhcnMsIGFlcyh4ID0gbnR2YXIsIHkgPSBuLCBmaWxsID0gZGlldCkpICsKZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArIAojZmFjZXRfZ3JpZCh+aW5mX3JvdXRlKSArClBsb3RUaGVtZTEgKwpEaWV0Y29sU2NhbGVfZmlsbAoKZGlmZl9zaGFyZWRfdmFycyA9IGdyb3VwX2J5KHNoYXJlZCwgbnR2YXIsIGRpZXQpICU+JSAKICB0YWxseSgpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZGlldCwgdmFsdWVzX2Zyb20gPSBuKSAlPiUgCiAgbXV0YXRlKGRpZmYgPSBhYnMoT2Jlc2UgLSBMZWFuKSkgJT4lIAogIGZpbHRlcihkaWZmID4gMikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJMZWFuIiwgIk9iZXNlIiksIG5hbWVzX3RvID0gYygiZGlldCIpKQogIApnZ3Bsb3QoZGlmZl9zaGFyZWRfdmFycywgYWVzKHggPSBudHZhciwgeSA9IHZhbHVlLCBmaWxsID0gZGlldCkpICsKZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiNmYWNldF9ncmlkKH5pbmZfcm91dGUpICsKUGxvdFRoZW1lMSArCkRpZXRjb2xTY2FsZV9maWxsCmBgYAoKCklzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiBBRiBvZiB0aGUgdmFyaWFudHMgZm91bmQgaW4gb2Jlc2UgYW5kIGxlYW4gZmVycmV0cz8KYGBge3J9CmdncGxvdChzaGFyZWQsIGFlcyh4ID0gbWlub3JmcmVxLCBmaWxsID0gZGlldCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMDEpICsKICBQbG90VGhlbWUxICsKICBmYWNldF9ncmlkKGluZl9yb3V0ZX5kaWV0KSArCiAgRGlldGNvbFNjYWxlX2ZpbGwKCm8gPSBmaWx0ZXIoZmVydW5pcXVlLCBpbmZfcm91dGUgPT0gIkluZGV4IiAmIGRpZXQgPT0gIk9iZXNlIikKbCA9IGZpbHRlcihmZXJ1bmlxdWUsIGluZl9yb3V0ZSA9PSAiSW5kZXgiICYgZGlldCA9PSAiTGVhbiIpCnQudGVzdChvJG1pbm9yZnJlcSwgbCRtaW5vcmZyZXEpCiNub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQKYGBgCgpgYGB7cn0Kb2Jlc2VfaW5kZXggPSBmaWx0ZXIoZmVydW5pcXVlLCBkaWV0ID09ICJPYmVzZSIgJiBpbmZfcm91dGUgPT0gIkluZGV4IikgJT4lIHVuZ3JvdXAoKQpsZWFuX2luZGV4ID0gZmlsdGVyKGZlcnVuaXF1ZSwgZGlldCA9PSAiTGVhbiIgJiBpbmZfcm91dGUgPT0gIkluZGV4IikgJT4lIHVuZ3JvdXAoKQp0LnRlc3Qob2Jlc2VfaW5kZXgkbWlub3JmcmVxLCBsZWFuX2luZGV4JG1pbm9yZnJlcSkKIyBtZWFucyBhcmUgbm90IGRpZmZlcmVudAoKb2Jlc2VfY29udGFjdCA9IGZpbHRlcihmZXJ1bmlxdWUsIGRpZXQgPT0gIk9iZXNlIiAmIGluZl9yb3V0ZSA9PSAiQ29udGFjdCIpICU+JSB1bmdyb3VwKCkKbGVhbl9jb250YWN0ID0gZmlsdGVyKGZlcnVuaXF1ZSwgZGlldCA9PSAiTGVhbiIgJiBpbmZfcm91dGUgPT0gIkNvbnRhY3QiKSAlPiUgdW5ncm91cCgpCnQudGVzdChvYmVzZV9jb250YWN0JG1pbm9yZnJlcSwgbGVhbl9jb250YWN0JG1pbm9yZnJlcSkKIyBtZWFucyBhcmUgbm90IGRpZmZlcmVudAoKIyBRUV9QbG90OiBjb21wYXJlcyB0aGUgcXVhbnRpbGVzIG9mIHR3byBkaXN0cmlidXRpb25zLCB4ID15IHN1Z2dlc3RzIHRoZXkgYXJlIGRyYXduIGZyb20gdGhlIHNhbWUgZGlzdHJpYnV0aW9uCnFxbm9ybShvYmVzZV9pbmRleCRtaW5vcmZyZXEsIG1haW4gPSAiT2Jlc2UgSW5kZXggLSBUZXN0IG9mIE5vcm1hbCBEaXN0cmlidXRpb24iKQpxcW5vcm0obGVhbl9pbmRleCRtaW5vcmZyZXEsIG1haW4gPSAiTGVhbiBJbmRleCAtIFRlc3Qgb2YgTm9ybWFsIERpc3RyaWJ1dGlvbiIpCiMgbmVpdGhlciBkaXN0cmlidXRpb24gaXMgbm9ybWFsCnFxcGxvdChvYmVzZV9pbmRleCRtaW5vcmZyZXEsbGVhbl9pbmRleCRtaW5vcmZyZXEsIHhsYWIgPSAiT2Jlc2UgSW5kZXgiLCB5bGFiID0gIkxlYW4gSW5kZXgiKQoKcXFub3JtKG9iZXNlX2NvbnRhY3QkbWlub3JmcmVxLCBtYWluID0gIk9iZXNlIENvbnRhY3QgLSBUZXN0IG9mIE5vcm1hbCBEaXN0cmlidXRpb24iKQpxcW5vcm0obGVhbl9jb250YWN0JG1pbm9yZnJlcSwgbWFpbiA9ICJMZWFuIENvbnRhY3QgLSBUZXN0IG9mIE5vcm1hbCBEaXN0cmlidXRpb24iKQojIG5laXRoZXIgZGlzdHJpYnV0aW9uIGlzIG5vcm1hbApxcXBsb3Qob2Jlc2VfY29udGFjdCRtaW5vcmZyZXEsbGVhbl9jb250YWN0JG1pbm9yZnJlcSwgeGxhYiA9ICJPYmVzZSBDb250YWN0IiwgeWxhYiA9ICJMZWFuIENvbnRhY3QiKQoKIyBNYW5uLVdoaXRuZXktV2lsY294IHRlc3QgKE1hbm4tV2hpdG5leSBVIHRlc3QpOiBzYW1wbGVzIGFyZSBub3Qgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIGluZGVwZW5kZW50IG9mIGVhY2ggb3RoZXIKd2lsY294LnRlc3Qob2Jlc2VfaW5kZXgkbWlub3JmcmVxLGxlYW5faW5kZXgkbWlub3JmcmVxKQp3aWxjb3gudGVzdChvYmVzZV9jb250YWN0JG1pbm9yZnJlcSxsZWFuX2NvbnRhY3QkbWlub3JmcmVxKQojIGRpc3RyaWJ1dGlvbnMgYXJlIG5vdCBkaWZmZXJlbnQKCiMgS29sbW9nb3Jvdi1TbWlybm92IHRlc3Q6IHNhbXBsZXMgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCBhbmQgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlcgojICJzZW5zaXRpdmUgdG8gZGlmZmVyZW5jZXMgaW4gbG9jYXRpb24gYW5kIHNoYXBlIG9mIHRoZSBlbXBpcmljYWwgQ0RGcyBvZiB0aGUgdHdvIHNhbXBsZXMiCmtzLnRlc3Qob2Jlc2VfaW5kZXgkbWlub3JmcmVxLGxlYW5faW5kZXgkbWlub3JmcmVxKQprcy50ZXN0KG9iZXNlX2NvbnRhY3QkbWlub3JmcmVxLGxlYW5fY29udGFjdCRtaW5vcmZyZXEpCiMgZGlzdHJpYnV0aW9ucyBhcmUgbm90IGRpZmZlcmVudApgYGAKCg==